//////////////////////////////////////////////////////////////////////////

#ifndef _ASYNCCALLER_H_
#include "asynccaller.h"
#endif

//////////////////////////////////////////////////////////////////////////

#ifndef _BOOSTSERVICE_H_
#include "boostservice.h"
#endif

//////////////////////////////////////////////////////////////////////////

#include <boost/bind.hpp>
#include <iostream>

//////////////////////////////////////////////////////////////////////////

// Some boost typedefs
typedef boost::asio::deadline_timer DeadlineTimer;
typedef boost::asio::deadline_timer::duration_type DurationType;
typedef boost::posix_time::milliseconds Milliseconds;

//////////////////////////////////////////////////////////////////////////


AsyncCaller::~AsyncCaller()
{
    // Kill all deadline timers
    DeleteDeadlineTimers();
}


//////////////////////////////////////////////////////////////////////////


void AsyncCaller::AsyncCall( UserFunction _function, int _param, size_t _delay /*= 0 */ )
{
    // Get free deadline timer
    DeadlineTimer* deadlineTimer =
        static_cast<DeadlineTimer*>( GetFreeDeadlineTimer() );

    if (deadlineTimer)
    {
        // Set expiry time
        deadlineTimer->expires_from_now( Milliseconds(_delay) );

        // Asynchronous wait
        deadlineTimer->async_wait( boost::bind( &AsyncCaller::HandleCall,
                                                this,
                                                boost::asio::placeholders::error,
                                                _function,
                                                _param ) );
    }
}


//////////////////////////////////////////////////////////////////////////


void AsyncCaller::DeleteDeadlineTimers()
{
    // Kill all deadline timers
    for (size_t i = 0; i < m_DeadlineTimerVec.size(); ++i)
    {
        DeadlineTimer* deadlineTimer =
            static_cast<DeadlineTimer*>( m_DeadlineTimerVec[i] );

        if (deadlineTimer)
        {
            // Cancel wait operation before kill
            deadlineTimer->cancel();
            delete deadlineTimer;
        }
    }
}


//////////////////////////////////////////////////////////////////////////


void* AsyncCaller::GetFreeDeadlineTimer()
{
    // Examine all timers
    for (size_t i = 0; i < m_DeadlineTimerVec.size(); ++i)
    {
        // Get timer
        DeadlineTimer* deadlineTimer =
            static_cast<DeadlineTimer*>( m_DeadlineTimerVec[i] );

        if (deadlineTimer)
        {
            // If timer is busy
            DurationType expirityTime = deadlineTimer->expires_from_now();
            if ( expirityTime > DurationType() )
                // Get next one
                continue;

            else
                // Timer is free. Get it.
                return static_cast<void*>(deadlineTimer);
        }
    }

    // No free timers. Create new and return it
    return AddNewTimer();
}


//////////////////////////////////////////////////////////////////////////


void* AsyncCaller::AddNewTimer()
{
    // Create new deadline timer
    DeadlineTimer* deadlineTimer = new DeadlineTimer( BoostService::GetIOService() );

    // And put it to collection
    m_DeadlineTimerVec.push_back( static_cast<void*>(deadlineTimer) );

    // And return its pointer
    return m_DeadlineTimerVec.back();
}


//////////////////////////////////////////////////////////////////////////


void AsyncCaller::HandleCall( const boost::system::error_code& _error,
                              UserFunction _function,
                              int _param )
{
    if (!_error)
        _function(_param);

    else
        std::cout << _error.message() << std::endl;
}


//////////////////////////////////////////////////////////////////////////
